#include "conexion.h"
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>

int conexion_desconectar(conexion *c){
  conexion_set_status(c, CON_DESCONECTANDO); 
  close(c->socket);
  conexion_set_status(c, CON_DESCONECTADO); 
}


int conexion_write(conexion *origen, void *datos, int size){
  int r = send(origen->socket, datos, size, 0);
  if(r==-1){
    if(errno==EWOULDBLOCK){
      return 0;
    }else{
      //error
      return 1;
    }
  }
  return r;
}

int conexion_read(conexion *destino, void *datos, int size){
  int r = recv(destino->socket, datos, size, 0);
  if(r==-1){
    if(errno==EWOULDBLOCK){
      return 0;
    }else{
      //error
      return 1;
    }
  }
  return r;
}


int conexion_conectar(conexion *c, char *servidor){
  c->socket = socket(AF_INET, SOCK_STREAM, 0);
  fcntl(c->socket, F_SETFL, O_NONBLOCK);
  if(c->socket==-1){
    //manejar error
    return 1;
  }

  int puerto;
  char *p_dospuntos = servidor;
  while(*p_dospuntos!=':' && *p_dospuntos!='\0')p_dospuntos++;
  puerto = atoi(p_dospuntos+1);
  char serv_name[p_dospuntos-servidor+1];
  strncpy(serv_name, servidor, p_dospuntos-servidor+1);
  serv_name[p_dospuntos-servidor]='\0';
  printf(" Conectando a \"%s\" en puerto %d \n", serv_name, puerto);

  struct hostent *he;
  he = gethostbyname(serv_name);//no me acuerdo si le puedo dejar :puerto
  if(he==0){
    //manejar error
    // printf("host not found"); 
    return 1;
  }

  struct sockaddr_in ser_addr;
  ser_addr.sin_addr = *((struct in_addr*)he->h_addr);
  ser_addr.sin_family = AF_INET;
  ser_addr.sin_port = htons(puerto);
  memset(&(ser_addr.sin_zero), 8, sizeof(int));

  int r = connect(c->socket, (struct sockaddr *) &ser_addr, sizeof(ser_addr));
  if(r==-1 && errno==EINPROGRESS)
    conexion_set_status(c, CON_CONECTANDO); 
  conexion_set_status(c, CON_CONECTADO); 
}

int conexion_escuchar(conexion *c, int puerto){
  c->socket = socket(AF_INET, SOCK_STREAM, 0);
  fcntl(c->socket, F_SETFL, O_NONBLOCK);

  unsigned int clilen;
  struct sockaddr_in cli_addr, serv_addr;
  memset((char *)&serv_addr,0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET; // Tipo internet
  serv_addr.sin_port = htons(puerto);
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  if ( bind(c->socket, (struct sockaddr *)&serv_addr, (socklen_t)sizeof(struct sockaddr)) < 0 ){
    //error
    return 1;
  }
  listen(c->socket,10); // Escucho por conexiones
  conexion_set_status(c, CON_ABIERTO); 
  return 0;
}

int conexion_aceptar(conexion *a, conexion **nuevo_cliente, conexion_callback callback){
  int addrlen;
  struct sockaddr_in address;
  addrlen=sizeof(struct sockaddr_in);
  int new = accept(a->socket, (struct sockaddr *) &address, &addrlen);
  *nuevo_cliente=0; 
  if(new==-1){
    if(errno==EWOULDBLOCK){
      return 0;
    }else{
      //set error
      return 1;
    }
  }else{
    conexion_crear(nuevo_cliente, callback);
    (*nuevo_cliente)->socket=new;
    fcntl(new, F_SETFL, O_NONBLOCK);
    conexion_publish(*nuevo_cliente, CON_NUEVA_CONEXION, 0, 0); 
    conexion_set_status(*nuevo_cliente, CON_CONECTADO); 
  }
  return 0;
}


int conexion_procesar_conexion(conexion *c){
  //conexion_set_status(c, CON_CONECTADO); 
}


